/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package maze;

import java.util.LinkedList;
import java.util.Random;
import java.util.Scanner;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.StringTokenizer;
import java.awt.event.*;
import java.io.File;

/**
 *
 * @author Iskandar Sarkawi
 */
public class Maze implements ActionListener {

    //Some constants for game state/condition
    final public static int CONDITION_NOTHING = 0;
    final public static int CONDITION_WIN = 1;
    final public static int CONDITION_LOSE = 2;

    private int condition;

    private MazeGUI gui;

    //List of all bad bots
    private LinkedList<Robot> badBots = new LinkedList<Robot>();

    private Robot goodBot;

    private int width, height; //width and height of the map
    private int goalX, goalY; //home location for the good bot
    private Tile[][] map; // The map of the maze
    //private String fileName; // In case if you need to reset ad read the same file

    private boolean gameEnded;

    public Maze(){

//        String fileName;
//        System.out.println("Enter the map file: ");
//        Scanner in = new Scanner(System.in);
//        fileName = in.nextLine();
        readFile();

        condition = CONDITION_NOTHING;
        gameEnded = false;
        //readFile();
        
        gui = new MazeGUI(this);
    }

    public void readFile(){
        //BufferedReader reader = new BufferedReader(new FileReader("data/" + fileName));
        BufferedReader reader;
        try{
            //FileReader a = new FileReader(new File("C:\\javaiskandar\\Maze\\src\\maze\\data\\data1.txt"));
            FileReader a = new FileReader(new File("data\\data1.txt"));
            reader = new BufferedReader(a);
        } catch(Exception e){
            System.out.println("error :" + e.toString());
        }
        
        width = 20;
        height = 12;

        //Initialize the map
        map = new Tile[width][height];
        for(int row=0; row<width; row++){
            for(int col=0; col<height; col++){
                map[row][col] = new Tile();
            }
        }

        //Read starting location of a  good robot
        int goodBotX = 0;
        int goodBotY = 2;
        goodBot = new Robot(goodBotX, goodBotY);

        //Goal location
        goalX = 19;
        goalY = 0;

        //Read all bad robots
        int numBadBots = 2;
        String badBotLocation = "4,7,10,7";
        StringTokenizer tokenizer = new StringTokenizer(badBotLocation, ",");
        for(int i=0; i<numBadBots; i++){
            int botX = Integer.parseInt(tokenizer.nextToken());            
            int botY = Integer.parseInt(tokenizer.nextToken());            
            Robot badBot = new Robot(botX,botY);
            badBots.add(badBot);
        }

        //Read all obstacles
        int numObstacles = 13;
        String obstacleLocation = "2,3,3,3,4,3,2,4,4,4,12,2,13,2,14,2,14,3,9,6,10,6,11,6,9,7";
        tokenizer = new StringTokenizer(obstacleLocation, ",");
        for(int i=0; i<numObstacles; i++){
            int obstacleX = Integer.parseInt(tokenizer.nextToken());
            int obstacleY = Integer.parseInt(tokenizer.nextToken());
            map[obstacleX][obstacleY].setPassable(false);
        }
    }

    public void undo(){

        if(goodBot.canUndo()){
            System.out.println("can undo");//for testing purpose only
            goodBot.undo(map);
            for(int i=0; i<badBots.size(); i++){
                Robot bad = badBots.get(i);
                bad.undo(map);
            }
        }else
            System.out.println("cannot undo");//for testing purpose only
        
        gui.updateGraphics();
    }

    public void actionPerformed(ActionEvent e){
        String command = e.getActionCommand();
        boolean moved  = false;

        if(command.equals("Reset")){
            badBots.clear();
            gameEnded = false;
            condition = CONDITION_NOTHING;
            readFile();
            gui.updateGraphics();
        }

        if(command.equals("Undo"))
            undo();

        //Most buttons yield no effect once the game ended
        if(gameEnded) return;

        if (command.equals("Up")){
            if(isEmptyTile(goodBot.getX(), goodBot.getY()-1)){
                goodBot.saveLocation();
                goodBot.moveUp(map);
                moved = true;
            }
        }else if(command.equals("Left")){
            if(isEmptyTile(goodBot.getX()-1, goodBot.getY())){
                goodBot.saveLocation();
                goodBot.moveLeft(map);
                moved = true;
            }
        }else if(command.equals("Right")){
            if(isEmptyTile(goodBot.getX()+1, goodBot.getY())){
                goodBot.saveLocation();
                goodBot.moveRight(map);
                moved = true;
            }
        }else if(command.equals("Down")){
            if(isEmptyTile(goodBot.getX(), goodBot.getY()+1)){
                goodBot.saveLocation();
                goodBot.moveDown(map);
                moved = true;
            }
        }else if(command.equals("Stay")){
            goodBot.saveLocation();
            moved = true;
        }

        //Check for win condition
        if(goodBot.getX() == goalX && goodBot.getY() == goalY){
            condition = CONDITION_WIN;
            endGame();
        }


        if(moved){
            gui.updateGraphics();

            Thread t = new Thread(new Runnable(){
                public void run(){
                    moveBadBots();
                }
            });
            t.start();
            
        }

    }

    public boolean isEmptyTile(int x, int y){
        if(x<0 || x>=width || y<0 || y>=width)
            return false;
        if(map[x][y].isFree())
            return true;
        return false;
    }

    public void moveBadBots(){

        if(gameEnded) return; //no point of moving the bad bots when the game ends
        

        //Repeat the robot movement to 2 steps. This way the bad robot moves faster
        for(int moveCounter=0; moveCounter<2; moveCounter++){
            for(int i=0; i<badBots.size(); i++){
                boolean moved = false;
                Robot bad = badBots.get(i);

                //Try to move robot to left or right (if no obstacles exists)
                if(bad.getX() > goodBot.getX()){
                    if(bad.getX()-1 == goodBot.getX() && bad.getY() == goodBot.getY())
                        condition = CONDITION_LOSE;
                    if(isEmptyTile(bad.getX()-1, bad.getY())){
                        bad.moveLeft(map);
                        moved = true;
                    }
                }
                else if(bad.getX() < goodBot.getX()){
                    if(bad.getX()+1 == goodBot.getX() && bad.getY() == goodBot.getY())
                        condition = CONDITION_LOSE;
                     if(isEmptyTile(bad.getX()+1, bad.getY())){
                         bad.moveRight(map);
                         moved = true;
                     }

                }

                //If the robot can't move to left or right then move the robot up or down
                if(!moved){
                    if(bad.getY() > goodBot.getY()){
                        if(bad.getX() == goodBot.getX() && bad.getY()-1 == goodBot.getY())
                            condition = CONDITION_LOSE;
                        if(isEmptyTile(bad.getX(), bad.getY()-1)){
                            bad.moveUp(map);
                            moved = true;
                        }
                    }
                    else if(bad.getY() < goodBot.getY()){
                        if(bad.getX() == goodBot.getX() && bad.getY()+1 == goodBot.getY())
                            condition = CONDITION_LOSE;
                        if(isEmptyTile(bad.getX(), bad.getY()+1)){
                            bad.moveDown(map);
                            moved = true;
                        }
                    }
                }

                if(condition == CONDITION_LOSE)
                    endGame();
            }

            try{
                Thread.sleep(100);
            }
            catch(Exception e){
                e.printStackTrace();
            }
            gui.updateGraphics();
        }
        
    }

    public void endGame(){
        if (condition == CONDITION_WIN){
            System.out.println("You win");
            gui.setStatus("You cleared the stage!");
            gameEnded = true;
        }
        else if(condition == CONDITION_LOSE){
            System.out.println("You Lost");
            gui.setStatus("Try again dude!");
            gameEnded = true;
        }
    }

    //Getters and setters
    public Tile[][] getMap(){
        return map;
    }

    public LinkedList<Robot> getBadBots(){
        return badBots;
    }

    public Robot getGoodBot(){
        return goodBot;
    }

    public int getWidth(){
        return width;
    }

    public int getHeight(){
        return height;
    }

    public int getGoalX(){
        return goalX;
    }

    public int getGoalY(){
        return goalY;
    }

    public int getCondition(){
        return condition;
    }

    public static void main(String[] args) {
        // TODO code application logic here
        Maze maze = new Maze();
    }

}
